Fix overriding mixing with default features
authorAlex Crichton <alex@alexcrichton.com>
Fri, 17 Mar 2017 23:12:11 +0000 (16:12 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Fri, 17 Mar 2017 23:12:11 +0000 (16:12 -0700)
Previously Cargo had a bug where if a crate *without* a default feature was
overridden with one that did indeed have a default feature then the default may
not end up getting activated by accident. The fix was to avoid returning too
quickly hen activating dependencies until after we've inspected and learned
about replacements.

Closes #3812

src/cargo/core/resolver/mod.rs
tests/overrides.rs

index b60ed10e358726b81e5fc495ecad52d2d8d30313..4943f6fe2fa55786d161279a3f19bd020957b864 100644 (file)
@@ -316,15 +316,13 @@ fn activate(cx: &mut Context,
                               candidate.summary.package_id().clone());
     }
 
-    if cx.flag_activated(&candidate.summary, method) {
-        return Ok(None);
-    }
+    let activated = cx.flag_activated(&candidate.summary, method);
 
     let candidate = match candidate.replace {
         Some(replace) => {
             cx.resolve_replacements.insert(candidate.summary.package_id().clone(),
                                            replace.package_id().clone());
-            if cx.flag_activated(&replace, method) {
+            if cx.flag_activated(&replace, method) && activated {
                 return Ok(None);
             }
             trace!("activating {} (replacing {})", replace.package_id(),
@@ -332,6 +330,9 @@ fn activate(cx: &mut Context,
             replace
         }
         None => {
+            if activated {
+                return Ok(None)
+            }
             trace!("activating {}", candidate.summary.package_id());
             candidate.summary
         }
index a44a9cb4188605c774dc79927aeb55166336d051..4095cedf22a74013fd7205ac09181da0cec037f7 100644 (file)
@@ -1104,3 +1104,61 @@ warning: path override for crate `foo` has altered the original list of
 dependencies; the dependency on `bar` was either added or\
 "));
 }
+
+#[test]
+fn override_with_default_feature() {
+    Package::new("another", "0.1.0").publish();
+    Package::new("another", "0.1.1")
+            .dep("bar", "0.1")
+            .publish();
+    Package::new("bar", "0.1.0").publish();
+
+    let p = project("local")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "local"
+            version = "0.0.1"
+            authors = []
+
+            [dependencies]
+            bar = { path = "bar", default-features = false }
+            another = "0.1"
+            another2 = { path = "another2" }
+
+            [replace]
+            'bar:0.1.0' = { path = "bar" }
+        "#)
+        .file("src/main.rs", r#"
+            extern crate bar;
+
+            fn main() {
+                bar::bar();
+            }
+        "#)
+        .file("bar/Cargo.toml", r#"
+            [package]
+            name = "bar"
+            version = "0.1.0"
+            authors = []
+
+            [features]
+            default = []
+        "#)
+        .file("bar/src/lib.rs", r#"
+            #[cfg(feature = "default")]
+            pub fn bar() {}
+        "#)
+        .file("another2/Cargo.toml", r#"
+            [package]
+            name = "another2"
+            version = "0.1.0"
+            authors = []
+
+            [dependencies]
+            bar = { version = "0.1", default-features = false }
+        "#)
+        .file("another2/src/lib.rs", "");
+
+    assert_that(p.cargo_process("run"),
+                execs().with_status(0));
+}